#include<iostream>
#include<pthread.h>
#include<vector>
#include<unistd.h>
#include<cassert>
#include<cstdio>

using namespace std;
// 用pthread_join接口实现线程等待的实验

// 当成结构体来用
class ThreadDate
{
public:
    int _number;
    pthread_t _tid;
    char _namebuffer[64];
};

class ThreadReturn
{
public:
    int exit_code;
    int exit_return;
};

void* thread_routine(void* args)
{
    // 为了保证主线程for循环完毕之后，将所有新线程的信息先打印出来，让所有新线程都先等一会
    sleep(1); 

    // 把每个新线程的名字打印出来
    ThreadDate* td = static_cast<ThreadDate*>(args); // 安全的进行强制类型转换
    int cnt = 3;
    while(cnt)
    {
        // 将每个线程的名字利用传进来的结构体打印出来
        printf("new thread's name: %s, cnt: %d\n", td->_namebuffer, cnt--);
        sleep(1); 
    }

    ThreadReturn* tr = new ThreadReturn();
    tr->exit_code = 0;
    tr->exit_return = td->_number;
    return (void*)tr;

    //用pthread_exit也可以实现返回一个返回值
    // pthread_exit((void*)td->_number);

    // return  (void*)td->_number; //4字节int类型，直接放到8字节指针类型，c语言知识
}

int main()
{
    // 创建一批新线程
    vector<ThreadDate*> tds;
    for(int i = 1; i <= 10; i++)
    {
        ThreadDate* td = new ThreadDate(); 
        // 给每个新线程不一样的名字
        snprintf(td->_namebuffer, sizeof(td->_namebuffer), "%s %d", "thread", i);
        td->_number = i;
        int n = pthread_create(&td->_tid, nullptr, thread_routine, td); //直接传td进去, 结构体不会被共享
        // assert(n == 0);
        // (void)n;
        tds.push_back(td);
    }

    // 将所有新线程都创建完毕之后，输出所有新线程的信息
    for(auto& td : tds)
    {
        cout << "create thread：" << td->_namebuffer << " : " << "tid：" << td->_tid << endl;
    }

    // 等待所有的新线程【主线程如果不等待完所有的新线程，就会阻塞在这里，这里是阻塞式等待】
    for(auto& iter : tds)
    {
        // void* ret = nullptr;
        ThreadReturn* ret = nullptr; //通过ret这个参数拿到线程执行函数的返回值
        int n = pthread_join(iter->_tid, (void**)&ret); //&ret是ThreadReturn**，要强转一下才能传进去
        assert(n == 0);
        // 等待成功之后，为了让实验现象更明显，我们将它输出出来
        // cout << iter->_namebuffer << " wait success! | return: " << (long long)ret << endl;
        cout << iter->_namebuffer << " wait success! | exit_code: " << ret->exit_code << " | exit_return: " << ret->exit_return << endl;
        delete iter; //集中在for循环释放资源
    }

    cout << "------------------------------------" << endl; //等待玩打个横线，好看，喜欢

    return 0; 
}